﻿// -------------------------------------------------------------------------
//    @FileName         :    NFOperatingStatistcsMgr.cpp
//    @Author           :    gaoyi
//    @Date             :    24-7-30
//    @Email            :    445267987@qq.com
//    @Module           :    NFOperatingStatistcsMgr
//
// -------------------------------------------------------------------------

#include "NFOperatingStatistcsMgr.h"

#include "proto_svr_common.pb.h"

NFOperatingStatistcsMgr::NFOperatingStatistcsMgr()
{
}

NFOperatingStatistcsMgr::~NFOperatingStatistcsMgr()
{
}

int NFOperatingStatistcsMgr::Initialize(int iLogInterval, bool bIsLog)
{
	m_tLastTick = NFGetSecondTime();
	m_iInterval = iLogInterval;
	m_bIsLog = bIsLog;

	m_sessionMsgStatistic.Initialize();
	m_msgStatistic.Initialize();
	m_modulaStatistic.Initialize();
	return 0;
}

void NFOperatingStatistcsMgr::Tick()
{
	if (m_bIsLog)
	{
		DoLog();
	}
}

int NFOperatingStatistcsMgr::DoLog()
{
	std::string log;
	log += m_sessionMsgStatistic.ToLog();
	log += m_msgStatistic.ToLog();
	log += m_modulaStatistic.ToLog();
	LOG_STATISTIC("{}", log);
	return 0;
}

int NFOperatingStatistcsMgr::StopServer()
{
	return 0;
}

int CSessionMsgInfoStatistic::Initialize()
{
	m_astInfo.resize(m_astInfo.max_size());
	m_iTime = NFGetSecondTime();
	return 0;
}

SingleSessionStatistic* CSessionMsgInfoStatistic::GetRoleMsgStatistic(int iMsgID, uint64_t roleID, uint64_t uin)
{
	CHECK_EXPR(iMsgID >= 0 && iMsgID < (int)m_astInfo.size(), NULL, "iMsgID:{} roleID:{} uin:{}", iMsgID, roleID, uin);

	auto& msgInfo = m_astInfo[iMsgID];
	for (int i = 0; i < (int)msgInfo.info.size(); ++i)
	{
		bool isSame = false;
		if (roleID != 0)
		{
			if (msgInfo.info[i].role_id == roleID)
			{
				isSame = true;
			}
		}

		if (!isSame)
		{
			if (msgInfo.info[i].uin == uin)
			{
				isSame = true;
			}
		}

		if (isSame)
		{
			return &m_astInfo[iMsgID].info[i];
		}
	}

	return NULL;
}

int CSessionMsgInfoStatistic::Add(int iMsgID, int minCount, int maxCount, uint64_t roleID, uint64_t uin)
{
	CHECK_EXPR((iMsgID > 0 && iMsgID < (int)m_astInfo.size()), -1, "invalid msg:{} roleID:{} uin:{}", iMsgID, roleID, uin);

	auto& msgInfo = m_astInfo[iMsgID];
	msgInfo.msg_id = iMsgID;
	SingleSessionStatistic* tmpRoleStatis = GetRoleMsgStatistic(iMsgID, roleID, uin);
	if (tmpRoleStatis)
	{
		tmpRoleStatis->role_id = roleID;
		tmpRoleStatis->uin = uin;
		if (tmpRoleStatis->min_count < minCount)
			tmpRoleStatis->min_count = minCount;

		if (tmpRoleStatis->max_count < maxCount)
			tmpRoleStatis->max_count = maxCount;
	}
	else
	{
		if (msgInfo.info.size() >= msgInfo.info.max_size())
		{
			for (int i = 0; i < (int)msgInfo.info.size(); ++i)
			{
				auto& stat = msgInfo.info[i];
				if (stat.min_count < minCount)
				{
					stat.min_count = minCount;
					stat.max_count = maxCount;
					stat.role_id = roleID;
					stat.uin = uin;
				}
			}
		}
		else
		{
			SingleSessionStatistic stat;
			stat.min_count = minCount;
			stat.max_count = maxCount;
			stat.role_id = roleID;
			stat.uin = uin;
			msgInfo.info.push_back(stat);
		}
	}

	return 0;
}

std::string CSessionMsgInfoStatistic::ToLog()
{
	std::string str;
	if (NFGetSecondTime() - m_iTime < 3600)
		return str;

	m_iTime = NFGetSecondTime();
	proto_ff::SessionMsgStatisticInfo tmpStatistic;

	for (int i = 0; i < (int)m_astInfo.size(); ++i)
	{
		if (m_astInfo[i].msg_id > 0)
		{
			m_astInfo[i].ToPb(tmpStatistic.add_all_msg());
		}
	}

	if (tmpStatistic.all_msg_size() > 0)
	{
		NFProtobufCommon::ProtoMessageToJson(tmpStatistic, &str);
	}

	return str;
}

CMsgStatistic::CMsgStatistic(): m_aiMsgIdx(CS_MAX, -1)
{
}

int CMsgStatistic::Initialize()
{
	return 0;
}

int CMsgStatistic::RegCategory(int iID, const std::string& pszName)
{
	if (!IsValidID(iID))
	{
		return -1;
	}

	m_astMsg.emplace_back();
	auto& data = m_astMsg.back();
	data.iMsgID = iID;
	data.szName = pszName;

	m_aiMsgIdx[iID] = m_astMsg.size() - 1;

	return 0;
}

int CMsgStatistic::Add(int iID, int Bytes, int iCostUs, int iIsFail, int iInOut, int iMulticastNum)
{
	if (!IsValidID(iID))
	{
		LOGSVR_ERROR("invalid id %d\n" << iID);
		return -1;
	}

	int iIndex = m_aiMsgIdx[iID];
	if (-1 == iIndex)
	{
		std::string name = proto_ff::Proto_CS_CMD_Name((proto_ff::Proto_CS_CMD)iID);

		if (name.size() == 0)
		{
			name = proto_ff::Proto_SvrMsgID_Name((proto_ff::Proto_SvrMsgID)iID);
		}

		RegCategory(iID, name);
		iIndex = m_aiMsgIdx[iID];

		LOGSVR_INFO("not reg : " << iID);
	}

	if (ENST_NET_IN == iInOut)
	{
		m_astMsg[iIndex].iRcvByte += Bytes;
		m_astMsg[iIndex].iRcvCount++;
		if (iIsFail)
		{
			m_astMsg[iIndex].iRcvFail++;
		}
	}
	else
	{
		m_astMsg[iIndex].iSendByte += Bytes;
		m_astMsg[iIndex].iSendCount++;
		if (iIsFail)
		{
			m_astMsg[iIndex].iSendFail++;
		}
		if (iMulticastNum == 0)
		{
			iMulticastNum = 1;
		}
		m_astMsg[iIndex].iRealSendByte += Bytes * iMulticastNum;
		m_astMsg[iIndex].iRealSendPkg += iMulticastNum;
	}

	m_astMsg[iIndex].iTotalCostUs += iCostUs;
	if (m_astMsg[iIndex].iMaxCostUs < iCostUs)
	{
		m_astMsg[iIndex].iMaxCostUs = iCostUs;
	}

	return 0;
}

std::string CMsgStatistic::ToLog()
{
	std::string log;
	int iAveUs = 0;
	NFStringUtility::SStringPrintf(&log, "\n%-35s%-10s%-8s%-8s%-12s%-8s%-12s%-12s%-8s%-13s%-10s%-10s\n",
								   "name", "InByte", "InPkg", "InFail", "OutByte", "OutPkg", "realoutbyte", "realoutpkg", "OutFail", "Cost(s)", "AveCost(us)", "MaxCost(us)");

	for (int i = 0; i < (int)m_astMsg.size(); ++i)
	{
		if (m_astMsg[i].szName.empty())
		{
			continue;
		}

		if ((m_astMsg[i].iRcvByte == 0) && (m_astMsg[i].iSendByte == 0))
		{
			continue;
		}

		iAveUs = (m_astMsg[i].iRcvCount + m_astMsg[i].iSendCount) > 0 ? (m_astMsg[i].iTotalCostUs / (m_astMsg[i].iRcvCount + m_astMsg[i].iSendCount)) : 0;
		NFStringUtility::SStringPrintf(&log, "%-35s %-10d%-8d%-8d"
									   "%-12d%-8d"
									   "%-12d%-12d"
									   "%-8d"
									   "%5d.%06d  %-9d%-8d\n",
									   m_astMsg[i].szName.c_str(), m_astMsg[i].iRcvByte, m_astMsg[i].iRcvCount, m_astMsg[i].iRcvFail,
									   m_astMsg[i].iSendByte, m_astMsg[i].iSendCount,
									   m_astMsg[i].iRealSendByte, m_astMsg[i].iRealSendPkg,
									   m_astMsg[i].iSendFail,
									   m_astMsg[i].iTotalCostUs / 1000000, m_astMsg[i].iTotalCostUs % 1000000, iAveUs, m_astMsg[i].iMaxCostUs
									  );

		if (log.size() >= MAX_STATISTIC_LEN)
		{
			LOGSVR_INFO("statistic len too short\n");
			return log;
		}

		m_astMsg[i].iRcvCount = 0;
		m_astMsg[i].iSendCount = 0;
		m_astMsg[i].iRcvFail = 0;
		m_astMsg[i].iSendFail = 0;
		m_astMsg[i].iTotalCostUs = 0;
		m_astMsg[i].iMaxCostUs = 0;
		m_astMsg[i].iRcvByte = 0;
		m_astMsg[i].iSendByte = 0;
		m_astMsg[i].iRealSendByte = 0;
		m_astMsg[i].iRealSendPkg = 0;
	}

	return log;
}

int CModulaStatistic::Initialize()
{
	m_aiModulaIdx.clear();
	m_aiModulaIdx.resize(m_aiModulaIdx.max_size());
	for (int i = 0; i < (int)m_aiModulaIdx.size(); i++)
	{
		m_aiModulaIdx[i] = -1;
	}
	m_astModula.clear();
	return 0;
}

int CModulaStatistic::Add(int iID, const std::string& szName, int iCostUs)
{
	if (!IsModuleIDValid(iID))
	{
		return 0;
	}

	int iIndex = m_aiModulaIdx[iID];
	if (iIndex == -1)
	{
		m_astModula.emplace_back();
		auto& data = m_astModula.back();
		data.iID = iID;
		data.szName = szName;

		iIndex = m_astModula.size() - 1;
	}

	m_astModula[iIndex].iCount++;
	m_astModula[iIndex].iTotalCostTime += iCostUs;
	m_astModula[iIndex].iMaxCostTIme = std::max(m_astModula[iID].iMaxCostTIme, iCostUs);

	return 0;
}

std::string CModulaStatistic::ToLog()
{
	std::string log;
	NFStringUtility::SStringPrintf(&log, "\n%-30s%-15s%-20s%-20s%-20s%-20s%\n",
	"name", "id",  "count", "avarage(us)", "totalcost(s)", "maxcost(us)");

	for( int i = 0; i < MAX_MODULA_NUM; ++i )
	{
		if( m_aiModulaIdx[i] >= 0 )
		{
			int iAvarage = (m_astModula[i].iCount > 0) ? m_astModula[i].iTotalCostTime / m_astModula[i].iCount : 0;
			NFStringUtility::SStringPrintf(&log,  "%-30s%-15d%-20d%-20d%-20f%-20d\n",
											m_astModula[i].szName.data(),
											m_astModula[i].iID,
											m_astModula[i].iCount,
											iAvarage,
											m_astModula[i].iTotalCostTime *1.0f / 1000000,
											m_astModula[i].iMaxCostTIme
											);
			if(log.size() >= MAX_STATISTIC_LEN)
			{
				LOGSVR_INFO("statistic len too short\n");
				return log;
			}
		}
	}

	Initialize();

	return log;
}
